use std::{
    fs::File,
    io::{BufRead, BufReader},
    path::Path,
    sync::OnceLock as 單次鎖,
};
use Some as 有;

static 拼音對照表路徑: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/data/pinyin.tsv");

static 拼音對照表: 單次鎖<對照表> = 單次鎖::new();

#[derive(Default)]
struct 對照表 {
    標題行: Vec<String>,
    表: Vec<Vec<String>>,
}

impl 對照表 {
    fn 方案列序(&self, 方案名: &str) -> Option<usize> {
        self.標題行.iter().position(|名| 名 == 方案名)
    }
}

const 忽略行首: char = '#';
const 欄分隔符: char = '\t';

fn 讀取對照表(表路徑: impl AsRef<Path>) -> std::io::Result<對照表> {
    let mut 對照表 = 對照表::default();
    let 表 = BufReader::new(File::open(表路徑)?);
    let mut 諸行 = 表.lines();
    while let 有(行) = 諸行.next() {
        let 行 = 行?;
        if 行.starts_with(忽略行首) {
            continue;
        }
        對照表.標題行 = 行
            .split(欄分隔符)
            .map(str::trim)
            .map(ToString::to_string)
            .collect();
        break;
    }
    for 行 in 諸行 {
        let 行 = 行?;
        if 行.starts_with(忽略行首) {
            continue;
        }
        對照表.表.push(
            行.split(欄分隔符)
                .map(str::trim)
                .map(ToString::to_string)
                .collect(),
        );
    }
    Ok(對照表)
}

pub fn 拼音轉換<'a>(拼音: &'a str, 自拼音方案: &str, 至拼音方案: &str) -> &'a str {
    if 自拼音方案 == 至拼音方案 {
        return 拼音;
    }
    let 對照表 = 拼音對照表.get_or_init(|| 讀取對照表(拼音對照表路徑).unwrap());
    let Some(自拼音列序) = 對照表.方案列序(自拼音方案) else { return 拼音 };
    let Some(至拼音列序) = 對照表.方案列序(至拼音方案) else { return 拼音 };
    對照表
        .表
        .iter()
        .find(|拼音表| 拼音表[自拼音列序] == 拼音)
        .map_or("", |拼音表| &拼音表[至拼音列序])
}
